﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NPMonitor.Utility;

namespace NPMonitor.Launcher
{
    internal class FiddlerService
    {
        private FiddlerService() { }
        private static readonly FiddlerService instance = new FiddlerService();

        private Setting Setting = SettingFactory.Create();

        public static FiddlerService Instance
        {
            get { return FiddlerService.instance; }
        }

        public void Start()
        {
            if (!Setting.FiddlerEnable)
                return;

            Fiddler.FiddlerApplication.BeforeRequest += new Fiddler.SessionStateHandler(FiddlerApplication_BeforeRequest);
            Fiddler.FiddlerApplication.BeforeResponse += new Fiddler.SessionStateHandler(FiddlerHostStatistical);
            Fiddler.FiddlerApplication.AfterSessionComplete += new Fiddler.SessionStateHandler(FiddlerApplication_AfterSessionComplete);

            //设置默认端口，见setting.config配置的ListenPort
            Fiddler.FiddlerApplication.Startup(Setting.ListenPort, Flag);
        }

        private static Dictionary<string, SessionRecord> dic = new Dictionary<string, SessionRecord>();

        public void FiddlerApplication_BeforeRequest(Fiddler.Session oSession)
        {
            if (Setting.Matched(oSession.url))
            {
                oSession["id"] = Guid.NewGuid().ToString();
                dic.Add(oSession["id"], new SessionRecord
                {
                    RequestTime = DateTime.Now,
                    URL = oSession.url
                });
            }
        }

        public void FiddlerHostStatistical(Fiddler.Session oSession)
        {
            if (Setting.Matched(oSession.url))
            {
                string id = oSession["id"];
                if (dic.ContainsKey(id))
                {
                    dic[id].ResponseTime = DateTime.Now;
                }
            }
        }

        public void FiddlerApplication_AfterSessionComplete(Fiddler.Session oSession)
        {
            try
            {
                if (Setting.Matched(oSession.url))
                {
                    string id = oSession["id"];
                    if (dic.ContainsKey(id) && dic[id].ResponseTime.HasValue)
                    {
                        //ToDo:
                        dic.Remove(id);
                    }
                    Requests r = new Requests()
                    {
                        ProcessId = oSession.LocalProcessID,
                        Url = oSession.url,
                        //Location = Setting.Location,
                        MachineName = Setting.MachineName,
                        GatewayDeterminationTime = oSession.Timers.GatewayDeterminationTime,
                        DNSTime = oSession.Timers.DNSTime,
                        TCPConnectTime = oSession.Timers.TCPConnectTime,
                        ElapsedTime = oSession.Timers.ClientDoneResponse.Subtract(oSession.Timers.ClientBeginRequest).Milliseconds,
                        RequestTime = oSession.Timers.FiddlerBeginRequest,
                        HTTPSHandshake = oSession.Timers.HTTPSHandshakeTime,
                        ClientTime = oSession.Timers.ClientDoneRequest.Subtract(oSession.Timers.ClientConnected).Milliseconds
                          + oSession.Timers.ClientDoneResponse.Subtract(oSession.Timers.ClientBeginResponse).Milliseconds,
                        ServerTime = oSession.Timers.ServerDoneResponse.Subtract(oSession.Timers.ServerGotRequest).Milliseconds,
                        NetworkTime = oSession.Timers.ServerGotRequest.Subtract(oSession.Timers.ClientDoneRequest).Milliseconds
                          + oSession.Timers.ClientBeginResponse.Subtract(oSession.Timers.ServerBeginResponse).Milliseconds,

                        ClientConnected = oSession.Timers.ClientConnected,
                        ClientBeginRequest = oSession.Timers.ClientBeginRequest,
                        GotRequestHeaders = oSession.Timers.FiddlerGotRequestHeaders,
                        ClientDoneRequest = oSession.Timers.ClientDoneRequest,

                        ClientBeginResponse = oSession.Timers.ClientBeginResponse,
                        ClientDoneResponse = oSession.Timers.ClientDoneResponse
                    };
                    if (oSession.Timers.ServerConnected.Year > 1753)
                    {
                        r.ServerConnected = oSession.Timers.ServerConnected;
                    }
                    if (oSession.Timers.ServerGotRequest.Year > 1753)
                    {
                        r.ServerGotRequest = oSession.Timers.ServerGotRequest;
                    }
                    if (oSession.Timers.ServerBeginResponse.Year > 1753)
                    {
                        r.ServerBeginResponse = oSession.Timers.ServerBeginResponse;
                    }
                    if (oSession.Timers.FiddlerGotResponseHeaders.Year > 1753)
                    {
                        r.GotResponseHeaders = oSession.Timers.FiddlerGotResponseHeaders;
                    }
                    if (oSession.Timers.ServerDoneResponse.Year > 1753)
                    {
                        r.ServerDoneResponse = oSession.Timers.ServerDoneResponse;
                    }
                    r.Insert();
                    //service.SendRequest(r);
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
        }

        public void Stop()
        {
            if (!Setting.FiddlerEnable)
                return;

            //恢复监听之前的设置
            Fiddler.FiddlerApplication.Shutdown();
        }

        public void Dispose()
        {
            Stop();
        }

        public Fiddler.FiddlerCoreStartupFlags Flag
        {
            get
            {
                try
                {
                    Fiddler.FiddlerCoreStartupFlags flag =
                        (Fiddler.FiddlerCoreStartupFlags)Enum.Parse(typeof(Fiddler.FiddlerCoreStartupFlags), Setting.StartupFlag);

                    return flag;
                }
                catch
                {
                    return Fiddler.FiddlerCoreStartupFlags.Default;
                }
            }
        }
    }
}
